import Cesium, {
    Cartesian3,
    Cartographic,
    Math as cesiumMath,
    defined,
    Color,
    HeightReference,
    ColorBlendMode,
    BoundingSphere,
    Quaternion,
    Matrix3
} from 'cesium';
// @ts-ignore
import proj4 from 'proj4';
import {polygon as turfPolygon, rewind,circle} from '@turf/turf';

class GisTools {


    /**
     * 计算中心点
     * @param json  geoserver wfs 的单个的feature
     * @description geometry 是经纬度坐标串
     */
    computeCenter(json: any) {
        if (json.geometry.type === "MultiPolygon") {
            let positions = json.geometry.coordinates[0];
            let point: any = [];
            for (let i = 0; i < positions[0].length; i++) {
                point = point.concat(positions[0][i])
            }
            var hole = Cartesian3.fromDegreesArray(point);
            let centerpoint = BoundingSphere.fromPoints(hole).center;
            return centerpoint;
        }
    }

    /**
     * 鼠标的事件获取当前的点击位置的笛卡尔坐标
     * @param position 鼠标点击之后的evt.position
     */
    getCar3Position(viewer: any, position: any) {
        let car3: any = null;
        let pick = viewer.scene.pick(position);
        if (viewer.scene.globe.depthTestAgainstTerrain) {
            if (defined(pick)) {//获取到了pick
                car3 = viewer.scene.pickPosition(position);
            } else {
                let ray = viewer.camera.getPickRay(position);//获取一条射线
                car3 = viewer.scene.globe.pick(ray, viewer.scene);
            }
        } else {
            car3 = viewer.scene.camera.pickEllipsoid(position, viewer.scene.globe.ellipsoid);
        }
        return car3;
    }


    /**
     * 笛卡尔坐标转经纬度（含高度）
     * @param {Cartesian3 | {x:number,y:number,z:number}} cartesianObj
     * @return { latitude:number, longitude:number, altitude:number }
     */
    Cartesian3ToLngLat(cartesianObj: any) {
        const cartesian3 = new Cartesian3(cartesianObj.x, cartesianObj.y, cartesianObj.z);
        const cartographic = Cartographic.fromCartesian(cartesian3);
        const latitude = cesiumMath.toDegrees(cartographic.latitude);
        const longitude = cesiumMath.toDegrees(cartographic.longitude);
        const altitude = cartographic.height;
        return {latitude, longitude, altitude};
    }

    /**
     * 从wgs84转EPSG:2000的4490
     * @param {*} points
     */
    wgs84ToCgcs2000(points: any) {
        proj4.defs('EPSG:4490', 'GEOGCS["China Geodetic Coordinate System 2000",DATUM["China_2000",SPHEROID["CGCS2000",6378137,298.257222101,AUTHORITY["EPSG","1024"]],AUTHORITY["EPSG","1043"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4490"]]')
        proj4('EPSG:4326');
        let newPoints = [];
        if (points.length > 0) {
            for (var i = 0; i < points.length; i++) {
                let s = proj4(proj4('EPSG:4326'), proj4('EPSG:4490'), points[i])
                newPoints.push(s)
            }
        }
        return newPoints;

    }

    /**
     * 飞行到点
     * @param position  经纬度坐标[x,y]
     */
    cameraFlyToPoint(viewer: any, position: any, height: number = 200) {
        viewer.camera.flyTo({
            destination: Cartesian3.fromDegrees(position[0], position[1], height),
            orientation: {
                heading: cesiumMath.toRadians(175.0),
                pitch: cesiumMath.toRadians(-90.0),
                roll: 0.0
            }
        });
    }

    /**
     * 针对多面反选区域
     * @param viewer
     * @param positions
     */
    reverseSelectionArea(viewer: any, positions: Array<any>) {
        let polygon = turfPolygon(positions);
        return rewind(polygon);
    }

    /**
     * 计算椭圆的边缘位置
     * @param {object}  options
     * @param {number} options.semiMinorAxis：短半轴  eg:500
     * @param {number} options.semiMajorAxis：长半轴  eg:500
     * @param {number} options.rotation：旋转角度 法线 ,单位弧度-  eg:0
     * @param {object} options.position：中心点    eg:{"lon":113.24,"lat":21.21,"height":1}
     * @param {number} options.granularity：粒度 弧度  eg:Math.PI/150
     */
    computeEllipseEdgePositions(
        viewer: any,
        options: {
            position: Object,
            semiMinorAxis: number,
            semiMajorAxis: number,
            granularity: number,
            rotation: number
        }) {
        let {position,semiMinorAxis,semiMajorAxis,granularity,rotation} = options;
        let unitPosScratch = new Cartesian3();
        let eastVecScratch = new Cartesian3();
        let northVecScratch = new Cartesian3();
        let scratchCartesian1 = new Cartesian3();
        let center = Cartesian3.fromDegrees(position['lon'],position['lat'],position['height']);
        if(!granularity){
            //角度分割，  Math.PI=3.14=180度，Math.PI/180 平角180度分割180份
            granularity=Math.PI/180;
        }
        //限定分割范围，360度最少分割24份
        if (granularity > Math.PI / 12.0) {
            granularity = Math.PI / 12.0;
        }
        //限定分割范围，360度最大分割360份
        if (granularity < Math.PI / 180.0) {
            granularity = Math.PI / 180.0;
        }
        let aSqr = semiMinorAxis * semiMinorAxis;
        let bSqr = semiMajorAxis * semiMajorAxis;
        let ab = semiMajorAxis * semiMinorAxis;
        //得到一个欧几里得范数，从原点到向量终点的直线距离
        let mag = Cartesian3.magnitude(center);
        //欧几里得范数长度缩放为1,计算单位向量
        let unitPos = Cartesian3.normalize(center, unitPosScratch);
        //主要目的：计算一个叉积 是一个向量
        //UNIT_Z (0,0,1)  center(x,y,z)
        //几何意义-从向量模长：以 UNIT_Z 和   center 为边的平行四边形的面积
        //几何意义-从向量方向：叉积垂直于平行四边形构成的平面
        //计算得出一个朝向东方向的向量；
        let eastVec = Cartesian3.cross(Cartesian3.UNIT_Z, center, eastVecScratch);
        eastVec = Cartesian3.normalize(eastVec, eastVec);
        //得到一个北方向的向量
        let northVec = Cartesian3.cross(unitPos, eastVec, northVecScratch);
        //计算总分割的次数，取最大整数
        let numPts = Math.ceil((cesiumMath.PI * 2) / granularity);
        let deltaTheta = granularity;
        let theta = 0;

        let singleposition = scratchCartesian1;
        let i;
        let outerIndex = 0;
        let outerPositions = [];
        for (i = 0; i < numPts; i++) {
            theta = i * deltaTheta;
            singleposition = this.getPointOnEllipsoid(theta, rotation, northVec, eastVec, aSqr, ab, bSqr, mag, unitPos, singleposition);

            outerPositions[outerIndex++] = singleposition.x;
            outerPositions[outerIndex++] = singleposition.y;
            outerPositions[outerIndex++] = singleposition.z;
        }
        return  {
            numPts:numPts,
            outerPositions:outerPositions
        };

    }

    /**
   * 椭圆计算
   * @param {*} theta  弧度增量
   * @param {*} rotation 法线
   * @param {*} northVec  北向的向量
   * @param {*} eastVec   东向的向量
   * @param {*} aSqr  短半轴的平方
   * @param {*} ab   短半轴*长半轴
   * @param {*} bSqr  长半轴平方
   * @param {*} mag    中心点 欧几里得范数，从原点到向量终点的直线距离
   * @param {*} unitPos  中心点单位向量
   * @param {*} result  范围外边圆的坐标
   */
    getPointOnEllipsoid(theta:number, rotation:number, northVec:any, eastVec:any, aSqr:number, ab:number, bSqr:number, mag:any, unitPos:any, result:any) {
        let rotAxis = new Cartesian3();
        let tempVec = new Cartesian3();
        //三维空间中的旋转
        let unitQuat = new Quaternion();
        let rotMtx = new Matrix3();

        let azimuth = theta + rotation;
        //将一个向量放大或者缩小
        Cartesian3.multiplyByScalar(eastVec, Math.cos(azimuth), rotAxis);
        Cartesian3.multiplyByScalar(northVec, Math.sin(azimuth), tempVec);
        Cartesian3.add(rotAxis, tempVec, rotAxis);

        let cosThetaSquared = Math.cos(theta);
        cosThetaSquared = cosThetaSquared * cosThetaSquared;

        let sinThetaSquared = Math.sin(theta);
        sinThetaSquared = sinThetaSquared * sinThetaSquared;

        let radius = ab / Math.sqrt(bSqr * cosThetaSquared + aSqr * sinThetaSquared);
        let angle = radius / mag;

        // Create the quaternion to rotate the position vector to the boundary of the ellipse.
        Quaternion.fromAxisAngle(rotAxis, angle, unitQuat);
        Matrix3.fromQuaternion(unitQuat, rotMtx);

        Matrix3.multiplyByVector(rotMtx, unitPos, result);
        Cartesian3.normalize(result, result);
        Cartesian3.multiplyByScalar(result, mag, result);
        return result;
    }

    /**
     * 给定中心点计算环绕的圆上的点的坐标
     * @param {object}  options
     * @param {object} options.position：中心点    eg:{"lon":113.24,"lat":21.21,"height":1}
     * @param {number} options.radius：半径   单位千米
     * @param {number} options.steps：频数  default:64
     * @return [[jd,wd],[jd,wd]]
     */
    computeEllipseEdgePositionsTurf( options:any){
        let { position,radius, steps } = options;
        if(!position){ return; };
        let center = [position['lon'],position['lat']];
        let config:any = {steps: steps, units: 'kilometers', properties: {foo: 'bar'}};
        let circleFeature =circle(center, radius, config);
        let  positionLonLat=  circleFeature.geometry.coordinates[0];
        let newArr:any=[];
        positionLonLat.forEach((item:any)=>{
            newArr.push(Cesium.Cartesian3.fromDegrees(item[0],item[1],position['height']))
        })
        return newArr;
    }
}

export default new GisTools();
